(function ($, pilote, undefined){

    /************************/
    /* VARIABLES DE L'OBJET */
    /************************/
    
    // Variable 'alias' permettant de ne pas tout le temps à avoir a réécrire le prototype
    var proto = pilote.util.createClass('Game.object').prototype;
    
    // Variable permettant d'effectuer des appels de services
    proto.service = null;
    
    // Variable de gestion du template
    proto.template = null;
    
    // Variable de gestion des cartes et du plateau de jeu
    proto.hand = null;
    proto.board = null;
    
    // Variable de gestion des tours de jeu
	proto.turnToplay = null;
	
	// Variable de gestion des boucles d'action
	proto.idWaiting = null;
	proto.idMain = null;
	
	// Messages
	proto.endingMessage = { 0 : 'Partie en cours.'
		  , 1 : 'You win !!'
		  , 2 : 'You loose...'
		  , 3 : 'Equality, try again.'
		  }
    
    /***************************/
    /* CONSTRUCTEUR DE L'OBJET */
    /***************************/
    /**
     * Constructeur de l'objet
     * @param {Function} service : service permettant d'effectuer des appels de services
     * @param array listElement : liste des nom des cartes selectionnés par le joueur
     */
    proto.initialize = function (service, listElement) {
        var self = this;
        // Mise en place des éléments
        self.service = service;
        // Gestion du template
        self.template = $('#game');
        // Création des objets constituant le jeu
        self.board = new Board.object(self.template.find('.gameboard'));
        self.hand = new Hand.object(self.template.find('.hand'));
        // Gestion des actions
        self.bindEvenements(self);
        // Boucle principale du jeu
        self.waiting(self);
		self.idMain = setInterval(function () { self.main(self); }, 1000);
    };
    /*********************************/
    /* METHODES/FONCTIONS DE L'OBJET */
    /*********************************/
    /**
     * Méthode de liaison des éléments de la page aux actions
     */
    proto.bindEvenements = function (){
    	var self = this;
    	self.template.find('.hand li img').die('click').live('click', {instance : self}, self.handler.selectCard);
    	self.template.find('.gameboard .cell').die('click').live('click', {instance : self}, self.handler.playCard);
    	// Gestion des éléments de la box de fin du jeu 
    	$('#endOfGame .cards li img').die('click').live('click', {instance : self}, self.handler.selectEndOfGame);
    }
       
	/**
     * Méthode permettant de mettre en place le tour du joueur
     * @param bool play : variable permettant de savoir si le joueur doit jouer ou non
     */
    proto.setTurn = function (play) {
    	var self = this;
    	// Gestion du joueur
    	if (play){
    		self.turnToplay = true;
		}else{
			self.turnToplay = false;
		}
    }
    
   /**
    * Méthode de gestion de l'affichage d'un message
    * @param string msg : message à afficher
    */
	proto.setMsg = function (msg) {
	   var self = this;
	   if (!!msg){
		   self.template.find('.info input').val(msg);
	   }else{
		   if (self.turnToplay){
			   self.template.find('.info input').val('Your turn.');
		   }else{
			   self.template.find('.info input').val('CPU turn.');
		   }
	   }    	
	}

	/**
	 * Méthode de RAZ des éléments du manager
	 */
	proto.reset = function (){
		var self = this;
		// Reset des variables d'intervalle d'actions
		clearInterval(self.idMain);
		clearInterval(self.idWaiting);
		self.idMain = null;
		self.idWaiting = null;
		// Clean des objets
		self.board.reset();
		self.hand.reset();
		// On cache les éléments
		self.hand.hide();
	}

	/**
	 * Fonction de gestion de la fin du jeu
	 * @param object self : objet game
 	 * @param int type : type de fin 1(win), 2(loose), 3(équalité)
 	 * @param liste gain : liste des gains. {"CPU":['carte_1',....],...} 
	 */
	proto.endofGame = function(self,type,gain){
		// RAZ des éléments
		self.reset();
		
		// Gestion de la boite de dialogue
		var dlg = $('<div id="endOfGame"><div class="message"></div><div class="cards"></div></div>').appendTo('body');
		
		// Gestion des cartes.
		if (type == 1){
			var affichage = '',
				nbCard = 0;
			$.each(gain, function(opponent, listCard) {
				nbCard += 1;
				affichage += '<ul name="%s">'.format(opponent);
				$.each(createCardList(listCard), function(idx, card){
					affichage += '<li>%s</li>'.format(card.toString());
				});
				affichage += '</ul>';
			});
			// Affichage
			dlg.children('.message').html("Choose %s card :".format(nbCard));
			dlg.children('.cards').html(affichage);
		}		
		
		// Affichage de la boite de dialogue
		dlg.dialog({
			modal: true,
			resizable: false,
			title : self.endingMessage[type],
			width: 'auto',
			height: 'auto',
			closeOnEscape: false,
			buttons: { 'Ok': function() {
								if (self.endofGameBtnOk(type, gain)){
									// Fermeture de la boite de dialogue 
									$(this).dialog('close');
								}
								return false;
							}
					 },
			close: function(evt){
					// Gestion des gains
					self.endofGameActionClose(self,type, gain)
			},
		});
	}
	
	/**
	 * Fonction de gestion du bounton ok de la boite de dialogue de fin de jeu
	 * @param int type : type de fin 1(win), 2(loose), 3(équalité)
	 * @param liste gain : liste des gains. {"CPU":['carte_1',....],...}
	 */
	proto.endofGameBtnOk = function(type, gain){
		var retour = true
			nbCard = 0;
		
		if (type == 1){
			// Gestion du nombre de cartes à récupérer
			$.each(gain, function(opponent, listCard) {
				nbCard += 1;
			});
			// Test de la selection
			if ($('#endOfGame .cards li.selected').length == nbCard){
				// Fermeture de la boite de dialogue 
				retour = true
			}else{
				retour = false;
			}
		}
		return retour
	}
	
	/**
	 * Fonction de gestion des actions issuent de la fermeture de la boite de dialogue de fin de jeu
	 * @param object self : objet game
	 * @param int type : type de fin 1(win), 2(loose), 3(équalité)
	 * @param liste gain : liste des gains. {"CPU":['carte_1',....],...}
	 */
	proto.endofGameActionClose = function(self,type, gain){
		// Gestion d'un erreur
		var error = false;
		if (type == 1){
			// Récupération des noms des joueurs et des cartes selectionnées
			$.each($('#endOfGame .cards li.selected'), function(idx, li) {
				var opponentName = $(li).parent().attr('name'),
					cardName = gain[opponentName][$(li).children().attr('name')];
				// Appel de service pour la sauvegarde
				function handler(response){
					if (response.error == 0){
						error = true;
						pilote.dialog.info(response.msg,
						  		   'Information'
								   );
					}
				}
				self.service('release/%s/%s'.format(cardName,opponentName),								// Opération à effectuer
						{ },																			// Paramètres passés
						handler,																		// Fonction à effectuer au retour de la demande
						{ dataType: 'JSON', loader: 'Chargement en cours ...', 'async': false}																// Options
							);
			});
			
		}
		
		if (! error){
			// Redirection
			window.location = '/cartine/loadSelect/';
		}
	}
	
	
	/************************/
	/* HANDLERS DES ACTIONS */
	/************************/
	
	proto.handler = {};
	
	proto.handler.selectCard = function (evt) {
		var self = evt.data.instance,
			cardId = $(this).attr('name'),
			li = $(this).parent();
		// Gestion de l'affichage de la selection
		self.hand.selectCard(cardId, li);
	}
	
	proto.handler.playCard = function (evt) {
		var self = evt.data.instance
			idSquare = $(this).attr('name')
			card = self.hand.getSelectedCard();

		// Test pour savoir si une carte est selectionnée
		if (!!card){
			// Test pour savoir si la case est jouable
			if (self.board.setCard(idSquare, card)){
				// Appel au serveur
				function handler(response){
					if (response.error == 0){
						pilote.dialog.info(response.msg,
						  		   'Information'
								   );
					}else{
						// Mise en place des composants
						// - cartes
						self.hand.setData(createCardList(response.deck));
			    		self.hand.show();
			    		// - plateau
			    		self.board.setData(createCardList(response.board));
			    		self.board.show();
						// - gestion du joueur
			    		self.setTurn(response.player);
					}
				}
				self.service('play/%s/%s'.format(card.name,idSquare),	// Opération à effectuer
						{ },																			// Paramètres passés
						handler,																		// Fonction à effectuer au retour de la demande
						{ dataType: 'JSON', loader: 'Chargement en cours ...'}																// Options
						);
			}else{
				pilote.dialog.info('Impossible de jouer une carte ici.',
						  		   'Information'
								   );
			}
		}
	}
	
	proto.handler.selectEndOfGame = function (evt) {
		var ul = $(this).parent().parent(),
			li = $(this).parent();
		// Reset Selection
		$.each($(ul).children(li), function(idx, item){
			if ($(item).attr('class')=='selected'){
				$(item).removeAttr('class');
			}
		});
		// Selection de l'éléments
		li.attr('class','selected');
	}
	
	/*******************/
	/* ACTIONS BOUCLES */
	/*******************/
		
	/**
	 * Boucle permettant la gestion de la boucle d'appel
	 */
	proto.main = function (self) {
		// Message d'information
		self.setMsg();
		// Dans le cas ou c'est au joueur de jouer
		if (self.turnToplay){
			// On stop la boucle d'appel
			if (!!self.idWaiting){
				clearInterval(self.idWaiting);
				self.idWaiting = null;
			}
		}else{
			if (self.idWaiting == null){
				self.idWaiting = setInterval(function () { self.waiting(self); }, 1000);
			}
		}
	}
	
	/**
	 * Boucle principale d'appel du serveur
	 */
	proto.waiting = function () {
		var self = this;
		// Appel au serveur
		function handler(response){
			if (response.error == 0){
				pilote.dialog.info(response.msg,
				  		   'Information'
						   );
			}else{
				// Mise en place des composants
				// - main
	    		self.hand.setData(createCardList(response.deck));
	    		self.hand.show();
	    		// - plateau
	    		self.board.setData(createCardList(response.board));
	    		self.board.show();
				// - gestion du joueur
	    		self.setTurn(response.player);
	    		// Gestion de la fin du jeu
	    		if (response.endOfGame!=0){
	    			self.endofGame(self,response.endOfGame, response.gain);
	    		}
			}
		}
		self.service('refresh/',	// Opération à effectuer
				{ },				// Paramètres passés
				handler,			// Fonction à effectuer au retour de la demande
				{ dataType: 'JSON'}	// Options
				);
	}
    
})(window.jQuery, window.pilote);
